/*
 * Copyright (C) 2021 HiHope Open Source Organization .
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 *
 * limitations under the License.
 */

#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <unistd.h>
#include <time.h>

#include "net_demo.h"
#include "net_common.h"
#include "ohos_init.h"
#include "cmsis_os2.h"
#include "hi_wifi_api.h"
#include "lwip/ip_addr.h"
#include "lwip/netifapi.h"
#include "lwip/sockets.h"
#include "iot_gpio.h"
#include "iot_watchdog.h"
#include "iot_pwm.h"
#include "hi_io.h"
#include "hi_adc.h"
#include "hi_errno.h"

#define     IOT_GPIO_KEY     5

//定义快递数量
int G1_NUM_IN_LINE = 0;
int G2_NUM_IN_LINE = 0;
int G3_NUM_IN_LINE = 0;

//获取系统时间，用于执行中断
clock_t time1 ,time2;
//根据time1和time2计算时间间隔
double duration;


/**
 * @brief 获取电压值函数
 * 
 * @return 电压值 
 */

static float GetVoltage(void)
{
    unsigned int ret;
    unsigned short data;

    // 该函数通过使用hi_adc_read()函数来读取 HI_ADC_CHANNEL_2 的数值存储在data中， 
    // HI_ADC_EQU_MODEL_8 表示8次平均算法模式，
    // HI_ADC_CUR_BAIS_DEFAULT 表示默认的自动识别模式，
    ret = hi_adc_read((hi_adc_channel_index)HI_ADC_CHANNEL_2, &data, 
                    HI_ADC_EQU_MODEL_8, HI_ADC_CUR_BAIS_DEFAULT, 0);
    if (ret != HI_ERR_SUCCESS) {
        printf("ADC Read Fail\n");
        return;
    }
    
    // 最后通过 data * 1.8 * 4 / 4096.0 计算出实际的电压值。
    return (float)data * 1.8 * 4 / 4096.0;
}


//设置中断
static void OnButtonPressed(char* arg)
{
	
  (void*)arg;
  float voltage;

  //计算与上一次中断的时间间隔duration
  time1 = time2;
  time2 = time(NULL);
  duration = ((double)(time2 - time1));

  //当duration大于0.5时执行中断效果
	if(duration > 0.5){
    voltage = GetVoltage();
		if(voltage < 3){
			printf("vlt:%.3fV\n", voltage);
		}
		//排队人数加一
		if((voltage > 0.01) && (voltage < 0.4))
		{
			printf("Number of Zhongtong Express reducing one\n");
            G1_NUM_IN_LINE--;
            printf("Number of Zhongtong Express is %d\n",G1_NUM_IN_LINE);
		}

        if((voltage >= 0.4) && (voltage <= 0.8))
        {
            printf("Number of Yuantong Express reducing one\n");
            G2_NUM_IN_LINE--;
            printf("Number of Yuantong Express is %d\n",G2_NUM_IN_LINE);
        }

        if((voltage > 0.8) && (voltage <= 1.2))
        {
            printf("Number of Shunfeng Express reducing one\n");
            G3_NUM_IN_LINE--;
            printf("Number of Shunfeng Express is %d\n",G3_NUM_IN_LINE);
        }
        
	}
}


static char request[128] = "";
void TcpServerTest(unsigned short port)
{
    IoTGpioInit(IOT_GPIO_KEY);
    hi_io_set_func(IOT_GPIO_KEY, HI_IO_FUNC_GPIO_5_GPIO);
    IoTGpioSetDir(IOT_GPIO_KEY, IOT_GPIO_DIR_IN);
    hi_io_set_pull(IOT_GPIO_KEY, HI_IO_PULL_UP);
    IoTGpioRegisterIsrFunc(IOT_GPIO_KEY, IOT_INT_TYPE_LEVEL, 
                            IOT_GPIO_EDGE_FALL_LEVEL_LOW,
                            OnButtonPressed, NULL);

    ssize_t retval = 0;
    int backlog = 1;
    int sockfd = socket(AF_INET, SOCK_STREAM, 0); // TCP socket
    int connfd = -1;

    struct sockaddr_in clientAddr = {0};
    socklen_t clientAddrLen = sizeof(clientAddr);
    struct sockaddr_in serverAddr = {0};
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(port);  // 端口号，从主机字节序转为网络字节序
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); // 允许任意主机接入， 0.0.0.0


    retval = bind(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)); // 绑定端口
    if (retval < 0) {
        printf("bind failed, %ld!\r\n", retval);
        goto do_cleanup;
    }
    printf("bind to port %d success!\r\n", port);

    retval = listen(sockfd, backlog); // 开始监听
    if (retval < 0) {
        printf("listen failed!\r\n");
        goto do_cleanup;
    }
    printf("listen with %d backlog success!\r\n", backlog);

    while(1){

        // 接受客户端连接，成功会返回一个表示连接的socket，clientAddr参数将会携带客户端主机和端口信息；失败返回 -1
        // 此后的收、发都在表示连接的socket上进行；之后sockfd依然可以继续接受其他客户端的连接，
        // UNIX系统上经典的并发模型是“每个连接一个进程”——创建子进程处理连接，父进程继续接受其他客户端的连接
        // 鸿蒙liteos-a内核之上，可以使用UNIX的“每个连接一个进程”的并发模型
        // liteos-m内核之上，可以使用“每个连接一个线程”的并发模型

        connfd = accept(sockfd, (struct sockaddr *)&clientAddr, &clientAddrLen);
        if (connfd < 0) {
            printf("accept failed, %d, %d\r\n", connfd, errno);
            goto do_cleanup;
        }
        printf("accept success, connfd = %d!\r\n", connfd);
        printf("client addr info: host = %s, port = %d\r\n", inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));

        // 后续收、发都在表示连接的 socket 上进行；
        retval = recv(connfd, request, sizeof(request), 0);
        if (retval < 0) {
            printf("recv request failed, %ld!\r\n", retval);
            goto do_disconnect;
        }

        printf("recv request{%s} from client done!\r\n", request);


        char Str1[10];
        char Str2[10];
        char Str3[10];
        sprintf(Str1, "%d", G1_NUM_IN_LINE);
        sprintf(Str2, "%d", G2_NUM_IN_LINE);
        sprintf(Str3, "%d", G3_NUM_IN_LINE);

        if(strcmp(request ,"中通快递")==0){
            retval = send(connfd, Str1, strlen(Str1), 0);
            if (retval <= 0) {
                printf("send response failed, %ld!\r\n", retval);
                goto do_disconnect;
            }
            G1_NUM_IN_LINE++;
            printf("send response{%d} to client done!\r\n", G1_NUM_IN_LINE);
            printf("Number of Zhongtong Express adding one\n");
            printf("Number of Zhongtong Express is %d\n",G1_NUM_IN_LINE);
        }
        else if(strcmp(request ,"圆通快递")==0){
            retval = send(connfd, Str2, strlen(Str2), 0);
            if (retval <= 0) {
                printf("send response failed, %ld!\r\n", retval);
                goto do_disconnect;
            }
            G2_NUM_IN_LINE++;
            printf("send response{%d} to client done!\r\n", G2_NUM_IN_LINE);
            printf("Number of Yuantong Express adding one\n");
            printf("Number of Yuantong Express is %d\n",G2_NUM_IN_LINE);
        }
        else if(strcmp(request ,"顺丰快递")==0){
            retval = send(connfd, Str3, strlen(Str3), 0);
            if (retval <= 0) {
                printf("send response failed, %ld!\r\n", retval);
                goto do_disconnect;
            }
            G3_NUM_IN_LINE++;
            printf("send response{%d} to client done!\r\n", G3_NUM_IN_LINE);
            printf("Number of Shunfeng Express adding one\n");
            printf("Number of Shunfeng Express is %d\n",G3_NUM_IN_LINE);
        }
    }

    do_disconnect:
    sleep(1);
    close(connfd);
    sleep(1); // for debug

    do_cleanup:
    printf("do_cleanup...\r\n");
    close(sockfd);
}
    

SERVER_TEST_DEMO(TcpServerTest);